/**************************
***
*** dept: test
*** author: htj
***
*************************/
#include <streambuf>
#include <string>


namespace std {
/** Rw have the following interface:
 interface Rw
 {
  int write(const charT* s, streamsize size);
  int read(charT* s, streamsize size);
 };
**/

template<class stream,class Rw> class streamadaptor;
template<class Stream, class Rw> streamadaptor<Stream,Rw> MakeStreamAdaptor(Stream& s,Rw& rw);

template<class Rw , class charT, typename traits = char_traits<charT> >
class streambufadaptor: public basic_streambuf<charT,traits>
{
//    friend  streamadaptor<class Stream, Rw> MakeStreamAdaptor<>(Stream& s,Rw& rw);
//friend  class streamadaptor;
	Rw& _rw;
 	charT *_out;
 	streamsize _out_len;
 	charT *_in;
 	streamsize _in_len;
public:
 	streambufadaptor(const streambufadaptor&);
 	streambufadaptor& operator=(const streambufadaptor&);
public:
    typedef charT   char_type;
    typedef typename traits::int_type	    int_type;
    typedef typename traits::pos_type	    pos_type;
    typedef typename traits::off_type	    off_type;
    typedef traits			    traits_type;
 
	streambufadaptor(Rw& rw,ios_base::openmode mode = ios_base::in | ios_base::out | ios_base::binary): _rw(rw),_out(0),_out_len(0),_in(0),_in_len(0){
  		setg(_in,_in,_in);
  		setp(_out,_out + _out_len);
  		basic_streambuf<charT,traits>::_M_mode = mode;
 	}

 	~streambufadaptor() {
  		if(_out) free_out_buf();
  		if(_in) free_in_buf();
 	}

private:
 	void init_out_buf() {
  		_out_len = 512;
  		_out = new charT[_out_len];
  		setp(_out,_out + _out_len);
 	}

 	void free_out_buf() {
  		delete [] _out;
  		_out = 0;
  		_out_len = 0;
  		setp(0,0);
 	}
 	
	void init_in_buf() {
  		_in_len = 512;
  		_in = new charT[_in_len];
  		setg(_in,_in,_in);
 	}
 
	void free_in_buf() {
  		delete [] _in;
  		_in = 0;
  		_in_len = 0;
  		setg(_in,_in,_in);
 	}
protected:
 
	virtual int_type overflow(int_type c) {
  		if((basic_streambuf<charT,traits>::_M_mode & ios_base::out) == 0) {
       		return traits::eof();
    	}
  		sync();
  		if(traits::eq_int_type(c,traits::eof()) ) {
   			return traits::not_eof(c);
		} else {
   			if(pptr() == 0) init_out_buf();
   			return sputc(c);
  		}
 	}
 
	virtual int_type underflow() {
  		if((basic_streambuf<charT,traits>::_M_mode & ios_base::in) == 0) {
       		return traits::eof();
      	}
  		if(egptr() == 0) init_in_buf();
		if(egptr() == _in + _in_len) setg(_in,_in,_in);
  		
		int tmp = _rw.read(egptr(),_in + _in_len - egptr());
  		if(tmp < 1) return traits::eof();
  		setg(eback(),egptr(),egptr() + tmp);
  		
		return traits::to_int_type(*gptr());
 	}
 	
	virtual int sync() {
  		if(pptr() > pbase()) {
   			int tmp = pptr() - pbase();
   			int tmp1 = _rw.write(pbase(),tmp);
   			if(tmp1 < 1) {
    			return -1;
			}
   			if(tmp1 < tmp) {
    			memcpy(pbase(),pbase() + tmp1, tmp - tmp1);
    			setp(pbase(),epptr());
    			pbump(tmp1);
   			} else {
    			setp(pbase(),epptr());  
			}
  		}
  		return 0;
 	}
};

class streamadaptor_base{};

typedef const streamadaptor_base& StreamAdaptor;

template<class stream,class Rw>
class streamadaptor: public streamadaptor_base {
public:
 	typedef typename stream::char_type char_type;
 	typedef typename stream::traits_type traits_type;
private:
 	basic_ios<char_type,traits_type>& _stream ;
 	streambufadaptor<Rw,char_type,traits_type> _buff; 
 	basic_streambuf<char_type,traits_type>* _oldbuf;
public:
 	streamadaptor(stream& s,Rw& rw):_stream(s),_buff(rw) {
  		_oldbuf = _stream.rdbuf(&_buff);
 	}
 	
	~streamadaptor() {
  		_stream.rdbuf(_oldbuf);
 	}
 
	operator stream&(){ return _stream; }
 
	stream& get() { return _stream; }
};

template<class Stream, class Rw>
streamadaptor<Stream,Rw> MakeStreamAdaptor(Stream& s,Rw& rw) {
 	return streamadaptor<Stream, Rw>(s,rw);
};
#define CONCATENATE_DIRECT(s1, s2) s1##s2
#define CONCATENATE(s1, s2) CONCATENATE_DIRECT(s1, s2)
#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __LINE__)
#define STREAM_ADAPTOR StreamAdaptor ANONYMOUS_VARIABLE(streamAdaptor) = MakeStreamAdaptor

};
